from PyQt5 import QtGui, QtCore
from PyQt5.QtWidgets import *
from PyQt5.QtGui import *
from PyQt5.QtCore import *
import sys
import math

class Window(QMainWindow):
    def __init__(self):
        super().__init__()
        self.title = "PyQt5 Drawing Tutorial"
        self.top= 150
        self.left= 150
        self.width = 500
        self.height = 500
        self.InitWindow()
    def InitWindow(self):
        self.setWindowTitle(self.title)
        self.setGeometry(self.top, self.left, self.width, self.height)
        self.show()

    def buildPath(self, points):
        self.path = QtGui.QPainterPath()
        self.path.moveTo(points[0])
        factor = .1412
        for p in range(len(points) - 2):
            p2 = points[p + 1]
            target = QtCore.QLineF(p2, points[p + 2])
            reverseTarget = QtCore.QLineF.fromPolar(
                target.length() * factor, target.angle() + 180).translated(p2)
            if not p:
                self.path.quadTo(reverseTarget.p2(), p2)
            else:
                p0 = points[p - 1]
                p1 = points[p]
                source = QtCore.QLineF(p0, p1)
                current = QtCore.QLineF(p1, p2)
                targetAngle = target.angleTo(current)
                if 90 < targetAngle < 270:
                    ratio = abs(math.sin(math.radians(targetAngle)))
                    reverseTarget.setLength(reverseTarget.length() * ratio)
                reverseSource = QtCore.QLineF.fromPolar(
                    source.length() * factor, source.angle()).translated(p1)
                sourceAngle = current.angleTo(source)
                if 90 < sourceAngle < 270:
                    ratio = abs(math.sin(math.radians(sourceAngle)))
                    reverseSource.setLength(reverseSource.length() * ratio)
                self.path.cubicTo(reverseSource.p2(), reverseTarget.p2(), p2)

        final = QtCore.QLineF(points[-3], points[-2])
        reverseFinal = QtCore.QLineF.fromPolar(
            final.length() * factor, final.angle()).translated(final.p2())
        self.path.quadTo(reverseFinal.p2(), points[-1])
        
    def paintEvent(self, event):
        painter = QPainter(self)
        self.path = QPainterPath()
        points = [
            QPoint(20,40),
            QPoint(60,10),
            QPoint(100,50),
            QPoint(80,200),
            QPoint(200,300),
            QPoint(150,400),
            QPoint(350,450),
            QPoint(400,350),
            ]
        self.buildPath(points)
        # draw small red dots on each point
        painter.setPen(QtCore.Qt.red)
        painter.setBrush(QBrush(Qt.red))
        for i in range(len(points)):
            painter.drawEllipse(points[i], 3, 3)

        painter.setPen(QtCore.Qt.blue)
        painter.setBrush(QBrush(Qt.red, Qt.NoBrush)) #reset the brush
        #path.moveTo(points[0])

        # connect the points with blue straight lines
        #for i in range(len(points)-1):  # 1 less than length
        #    path.lineTo(points[i+1])

        # connect points with curve
        # for i in range(0,len(points),2):
        #     path.quadTo(points[i], points[i+1])

        painter.drawPath(self.path)

App = QApplication(sys.argv)
window = Window()
sys.exit(App.exec())